﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Ordinaire.Social.Data;

namespace Ordinaire.Social
{
    /// <summary>
    /// Exposes a person details in the contact data source.
    /// </summary>
    public class Person : Entity<int>
    {
        #region Variables

        /// <summary>
        /// The error message when property method "Name" is called.
        /// </summary>
        private const string NamePropertyErrorMessage = "Please use desired name instead: FirstName, MiddleName, or LastName";

        /// <summary>
        /// Person's first name.
        /// </summary>
        private string firstName;

        /// <summary>
        /// Person's full name.
        /// </summary>
        private string fullName;

        /// <summary>
        /// Person's middle name.
        /// </summary>
        private string middleName;

        /// <summary>
        /// Person's last name.
        /// </summary>
        private string lastName;

        /// <summary>
        /// The date of birth.
        /// </summary>
        private DateTime? dateOfBirth;

        /// <summary>
        /// The id of the default address.
        /// </summary>
        private int defaultAddressId;

        /// <summary>
        /// List of associated adddresses.
        /// </summary>
        private Dictionary<string, Address> addresses;

        #endregion

        #region Constructor

        /// <summary>
        /// Returns new instance of Ordinaire.Social.Person
        /// </summary>
        public Person()
        {
        }

        #endregion

        #region Property methods

        /// <summary>
        /// Gets or sets the date of birth.
        /// </summary>
        public DateTime? DateOfBirth
        {
            get { return this.dateOfBirth; }
            set { this.dateOfBirth = value; }
        }

        /// <summary>
        /// Gets or sets the first name.
        /// </summary>
        public string FirstName
        {
            get { return this.firstName; }
            set { this.firstName = value; }
        }

        /// <summary>
        /// Gets or sets the full name.
        /// </summary>
        public string FullName
        {
            get
            {
                if (!String.IsNullOrEmpty(fullName))
                {
                    return fullName;
                }

                fullName += this.firstName;
                fullName += (String.IsNullOrEmpty(this.middleName)) ? String.Empty : String.Format(" {0}", this.middleName);
                fullName += (String.IsNullOrEmpty(this.lastName))   ? String.Empty : String.Format(" {0}", this.lastName);
                return fullName;
            }
            set
            {
                this.fullName = value;

                string[] names  = value.ToNames();
                this.firstName  = names[0];
                this.middleName = names[1];
                this.lastName   = names[2];
            }
        }

        /// <summary>
        /// Gets or sets the last name.
        /// </summary>
        public string LastName
        {
            get { return this.lastName; }
            set { this.lastName = value; }
        }

        /// <summary>
        /// Gets or sets the middle name.
        /// </summary>
        public string MiddleName
        {
            get { return this.middleName; }
            set { this.middleName = value; }
        }

        /// <summary>
        /// Gets or sets the id of the default address.
        /// </summary>
        public int DefaultAddressId
        {
            get { return this.defaultAddressId; }
            set { this.defaultAddressId = value; }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <exception cref="System.NotImplementedException">Property "name" is obsolete for this class</exception>
        public override string Name
        {
            get { throw new NotImplementedException(NamePropertyErrorMessage); }
            set { throw new NotImplementedException(NamePropertyErrorMessage); }
        }

        /// <summary>
        /// Returns the default address if specified; otherwise the only associated address.
        /// </summary>
        public Address Address
        {
            get
            {
                Address defaultAddress = this.addresses.Values.Where(d => d.Id == this.defaultAddressId).SingleOrDefault();
                if (defaultAddress == null && this.addresses.Count == 1)
                {
                    return this.addresses.Values.FirstOrDefault();
                }
                return defaultAddress;
            }
        }

        /// <summary>
        /// Gets or sets list of associated addresses.
        /// </summary>
        public Dictionary<string, Address> Addresses
        {
            get { return this.addresses; }
            set { this.addresses = value; }
        }

        #endregion
    }
}
